#include<iostream>
#include "tablero.h"
#include "casillero.h"
#include "../bgi/graphics.h"

#include <stdlib.h>
#include <time.h>
#include <ctime>
using namespace std;

// Constructor
Tablero::Tablero(int cols, int filas, float mine_density)
{
	_pos_x = POS_X;
	_pos_y = POS_Y;
	_ancho_col = ANCHO_COL;
	_alto_fila = ALTO_FILA;
	_cant_col = cols;
	_cant_filas = filas;
	_cant_minas = (cols * filas) * mine_density;;
	_minas_restantes = _cant_minas;
	_juego_perdido = false;
	_celdas_reveladas = 0;

	for (int c = 0; c < _cant_col; c++)
	{
		for (int f = 0; f < _cant_filas; f++)
		{
			_casilleros[c][f] = NULL;
		}
	}

	int start_x = _pos_x;
	for (int c = 0; c < _cant_col; c++)
	{
		int start_y = _pos_y;
		for (int f = 0; f < _cant_filas; f++)
		{
			_casilleros[c][f] = new Casillero(start_x, start_y, start_x + _ancho_col, start_y + _alto_fila);
			start_y += _alto_fila;
		}
		start_x += _ancho_col;
	}
	set_minas();
	calcular_numeros();
}

// Destructor
Tablero::~Tablero()
{
	for (int c = 0; c < _cant_col; c++)
	{
		for (int f = 0; f < _cant_filas; f++)
		{
			if (_casilleros[c][f])
			{
				delete _casilleros[c][f];
				_casilleros[c][f] = NULL;
			}
		}
	}
}

// coloca una cantidad deseada de minas en posiciones al azar del tablero
void Tablero::set_minas()
{
	int minas = 0;
	int max = _cant_minas;
	int c;
	int f;
	srand (time(NULL));

	while (minas < max)
	{
		c = rand() % _cant_col;
		f = rand() % _cant_filas;
		if (_casilleros[c][f]->get_num() >= 0)
		{
			//_casilleros[c][f]->set_text("X");
			_casilleros[c][f]->set_num(-1);
			minas++;
		}
	}
}

// dibuja el marco del tablero, y llama a los casilleros a que se dibujen
void Tablero::dibujar()
{
	for (int c = 0; c < _cant_col; c++)
	{
		for (int f = 0; f < _cant_filas; f++)
		{
			_casilleros[c][f]->dibujar();
		}
	}
	rectangle(_pos_x - 10, _pos_y - 10, _pos_x + 10 + _ancho_col * _cant_col, _pos_y + 10 + _alto_fila * _cant_filas);
}

// calcula el numero de minas que contiene cada casillero a su alrededor
void Tablero::calcular_numeros()
{
	int c;
	int f;
	for (c = 0; c < _cant_col; c++)
	{
		for (f = 0; f < _cant_filas; f++)
		{
			if (_casilleros[c][f]->is_mina())
			{
				for (int x=-1; x<2; x++)
				{
					for (int y=-1; y<2; y++)
					{
						if (is_valid(c+x, f+y) && !_casilleros[c+x][f+y]->is_mina())
						{
							_casilleros[c+x][f+y]->incrementar();
						}
					}
				}
			}
		}
	}
}

// devuelve la posicion del borde derecho del tablero
int Tablero::get_right_bound()
{
	return _pos_x + (_cant_col * ANCHO_COL);
}

// devuelve la posicion del borde inferior del tablero
int Tablero::get_bottom_bound()
{
	return _pos_y + (_cant_filas * ALTO_FILA);
}

// realiza la accion que corresponde a un click izquierdo en la posicion indicada
void Tablero::revelar(int col, int fila)
{
	if (is_valid(col, fila))
	{
		if(!_casilleros[col][fila]->is_flagged())
		{
			if (_casilleros[col][fila]->is_oculto())
			{
				_casilleros[col][fila]->set_oculto(false);

				int num = _casilleros[col][fila]->get_num();

				if (num < 0) // es mina
				{
					revelar_tablero();
					_juego_perdido = true;
				}
				else if (num == 0) // esta vacio
				{
					revelar(col + 0, fila + 1);
					revelar(col + 0, fila - 1);
					revelar(col + 1, fila + 0);
					revelar(col - 1, fila + 0);

					revelar(col - 1, fila - 1);
					revelar(col - 1, fila + 1);
					revelar(col + 1, fila - 1);
					revelar(col + 1, fila + 1);
				}
			}
		}
	}
}

//Flaggea el casillero en la posicion indicada.
void Tablero::flag_casillero(int col, int fila)
{
	if(_casilleros[col][fila]->is_oculto())
	{
		if(_casilleros[col][fila]->is_flagged())
		{
			_casilleros[col][fila]->set_flag(false);
			_minas_restantes++;
		}
		else 
		{
			_casilleros[col][fila]->set_flag(true);
			_minas_restantes--;
		}
	}
}

// revela el contenido de todos los casilleros
void Tablero::revelar_tablero()
{
	int c;
	int f;
	for (c = 0; c < _cant_col; c++)
	{
		for (f = 0; f < _cant_filas; f++)
		{
			_casilleros[c][f]->set_oculto(false);
			_casilleros[c][f]->set_flag(false);
		}
	}
}

// verifica si una posicion del tablero es legal
bool Tablero::is_valid(int x, int y)
{
	bool result = true;
	if (x < 0 || x >= _cant_col || y < 0 || y >= _cant_filas)
		result = false;
	return result;
}

bool Tablero::is_juego_perdido()
{
	return _juego_perdido;
}

void Tablero::set_juego_perdido(bool juego_perdido)
{
	_juego_perdido = juego_perdido;
}

//Actualiza la cantidad de casilleros revelados.
void Tablero::update_reveladas()
{
	_celdas_reveladas = 0;
	for(int c = 0; c < _cant_col; c++)
	{
		for(int f = 0; f < _cant_filas; f++)
		{
			if (!_casilleros[c][f]->is_oculto())
			{
				_celdas_reveladas++;
			}
		}
	}
}

//Convierte la matriz a un vector para poder grabar la partida.
void Tablero::get_status(ty_vec_status status)
{
	int cont = 0;
	for(int c = 0; c < _cant_col; c++)
	{
		for(int f = 0; f < _cant_filas; f++)
		{
			status[cont].col = c;
			status[cont].fila = f;
			status[cont].num = _casilleros[c][f]->get_num();
			status[cont].oculto = _casilleros[c][f]->is_oculto();
			status[cont].flag = _casilleros[c][f]->is_flagged();
			cont++;
		}
	}
}

//Convierte el vector de estado en la matriz del tablero.
void Tablero::update_status(ty_vec_status status)
{
	for(int i = 0; i < _cant_col * _cant_filas; i++)
	{
		_casilleros[status[i].col][status[i].fila]->set_flag(status[i].flag);
		_casilleros[status[i].col][status[i].fila]->set_num(status[i].num);
		_casilleros[status[i].col][status[i].fila]->set_oculto(status[i].oculto);
	}
}

//Reinicializa el estado del tablero.
void Tablero::reset_tablero()
{
	_juego_perdido = false;
	_celdas_reveladas = 0;
	for (int c = 0; c < _cant_col; c++)
	{
		for (int f = 0; f < _cant_filas; f++)
		{
			_casilleros[c][f]->reset_casillero();
		}
	}
	set_minas();
	calcular_numeros();
}

int Tablero::get_pos_x(){return _pos_x;}
void Tablero::set_pos_x(int pos_x){_pos_x = pos_x;}

int Tablero::get_pos_y(){return _pos_y;}
void Tablero::set_pos_y(int pos_y){_pos_y = pos_y;}

int Tablero::get_cant_col(){return _cant_col;}
void Tablero::set_cant_col(int cant_col){_cant_col = cant_col;}

int Tablero::get_cant_filas(){return _cant_filas;}
void Tablero::set_cant_filas(int cant_filas){_cant_filas = cant_filas;}

int Tablero::get_ancho_col(){return _ancho_col;}
void Tablero::set_ancho_col(int ancho_col){_ancho_col = ancho_col;}

int Tablero::get_alto_fila(){return _alto_fila;}
void Tablero::set_alto_fila(int alto_fila){_alto_fila = alto_fila;}

int Tablero::get_current_time(){return _current_time;}
void Tablero::set_current_time(int current_time){_current_time = current_time;}

int Tablero::get_cant_minas(){return _cant_minas;}

int Tablero::get_cant_reveladas(){return _celdas_reveladas;}

int Tablero::get_minas_restantes(){	return _minas_restantes;}
void Tablero::set_minas_restantes(int minas_restantes) { _minas_restantes = minas_restantes; }

FILE* abrir_arch(const char * rutaynombre, const char * modo)
{
	FILE * archivo = NULL;
	if(!(modo == "rb" || modo == "rt") || arch_existe(rutaynombre))
	{
		archivo = fopen(rutaynombre, modo);
	}
	return archivo;
}

bool arch_existe(const char * rutaynombre){
FILE* archivo;

archivo = fopen(rutaynombre, "rb"); //Intento abrir el archivo en modo lectura, si no existe devuelvo false.
	if (archivo == NULL)
		return false;
	else
	{	//Si el archivo existe lo cierro y devuelvo true.
		fclose(archivo);
		return true;
	}
}
